package com.study.dto;

import cn.hutool.bloomfilter.BitMapBloomFilter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader.Feature;
import com.alibaba.fastjson2.TypeReference;
import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;
import reactor.netty.tcp.TcpClient;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author zhuzi
 * 2024/12/20 22:35
 */
public interface TencentDTO {


    class TenTool {
        public static BitMapBloomFilter bloomFilter = new BitMapBloomFilter(10);
        public static WebClient webClient = null;

        static {
            ConnectionProvider provider = ConnectionProvider.builder("fixed").maxConnections(200) // 最大连接数
                    .maxIdleTime(Duration.ofSeconds(60)) // 最大空闲时间
                    .maxLifeTime(Duration.ofSeconds(60)) // 最大存活时间
                    .pendingAcquireTimeout(Duration.ofSeconds(60)) // 等待获取时间
                    .pendingAcquireMaxCount(1000) // 挂起的获取最大计数
                    .build();

            TcpClient tcpClient = TcpClient.create(provider)//
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) // 连接超时时间
                    .doOnConnected(connection -> {
                        connection.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS)); // 读取超时
                        connection.addHandlerLast(new WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS)); // 写入超时
                    });

            HttpClient httpClient = HttpClient.from(tcpClient).keepAlive(true) // 启用保持连接
                    .responseTimeout(Duration.ofSeconds(10)); // 响应超时时间
            webClient = WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient)).build();
        }
    }

    @Data
    @Accessors(chain = true)
    class TenRespRootDTO<T> {
        private int code;
        private String msg;
        private TenPage<T> data;
    }

    @Data
    @Accessors(chain = true)
    class TenPage<T> {
        private List<T> rankList;
        private int offset;
        private int total;
    }

    /**
     * 腾讯自选股-行情-可转债列表
     * <p>
     */
    @Data
    @Accessors(chain = true)
    class HqKzzDTO {
        /**
         * 可转债代码 sz123244
         */
        private String code;
        /**
         * 到期日
         */
        private LocalDate dqrq;
        /**
         * 到期赎回价
         */
        private BigDecimal dqshj;
        /**
         * 换手率
         */
        private BigDecimal hsl;
        /**
         * 可转债名称
         */
        private String name;
        /**
         * 评级
         */
        private String pj;
        /**
         * 151.99
         */
        private BigDecimal sd;
        /**
         * 5分钟涨速
         */
        private String speed;
        /**
         * 上市日期
         */
        private LocalDate ssrq;

        private String state;
        /**
         * 股票代码(sz sg)
         */
        private String stockCode;
        private String stockName;
        /**
         * 股票正股涨速
         */
        private String stockSpeed;
        /**
         * 正股类型 ZQ-KZZ
         */
        private String stockType;
        /**
         * 正股涨幅
         */
        private BigDecimal stockZdf;
        /**
         * 正股 开盘价
         */
        private BigDecimal stockZtj;
        /**
         * 正股股价
         */
        private BigDecimal stockZxj;
        /**
         * 剩余规模(W)
         */
        private BigDecimal sygm;
        /**
         * 可转债成交额(W)
         */
        private BigDecimal turnover;
        /**
         * 可转债涨跌幅
         */
        private BigDecimal zdf;
        /**
         * 5日涨跌幅
         */
        private BigDecimal zdfD5;
        /**
         * 转股价
         */
        private BigDecimal zgj;

        /**
         * 转股价值
         */
        private BigDecimal zgjz;
        /**
         * 转股溢价率
         */
        private BigDecimal zgyjl;
        /**
         * 最新价
         */
        private BigDecimal zxj;
    }

    @Data
    @Accessors(chain = true)
    class TenHintDTO {
        private String name;
        /**
         * 最新价
         */
        private BigDecimal zxj;

        /**
         * 可转债涨跌幅
         */
        private BigDecimal zdf;

        /**
         * 正股涨幅
         */
        private BigDecimal stockZdf;

        /**
         * 涨跌幅相差
         */
        private BigDecimal subZdf;


        /**
         * 涨跌幅 设置 (可转债涨幅大于1 且差值大于0.5)
         *
         * @param hintDTO
         * @return
         */
        static boolean predicate(TenHintDTO hintDTO) {
            return Objects.nonNull(hintDTO) &&//
                    NumberUtil.isGreaterOrEqual(hintDTO.getZdf(), new BigDecimal("1")) &&//
                    NumberUtil.isGreaterOrEqual(hintDTO.getSubZdf(), new BigDecimal("1.5"));
        }

        public static TenHintDTO build(HqKzzDTO hqKzzDTO) {
            try {
                TenHintDTO tenHintDTO = new TenHintDTO();
                BeanUtils.copyProperties(hqKzzDTO, tenHintDTO);
                tenHintDTO.setSubZdf(NumberUtil.sub(tenHintDTO.getZdf(), tenHintDTO.getStockZdf()));
                return tenHintDTO;
            } catch (BeansException e) {
            }
            return null;
        }


        public String ding() {
            //松原转债223.56|20|2.28 |差17.72
            return StrUtil.format("{}|{}|{}|{}|差{}", name, zxj, zdf, stockZdf, subZdf);
        }
    }

    static void main(String[] args) {

        for (int i = 0; i < 3; i++) {
            //ThreadUtil.sleep(500);
            extracted();

        }
    }

    static boolean extracted() {
        String url = "https://proxy.finance.qq.com/cgi/cgi-bin/rank/hs/getBondRankList?board_type=convertible&sort_type=priceRatio&direct=down&count={}&offset={}&_rndtime={}&buildType=store&check=-1&lang=zh_CN";
        String body = TenTool.webClient.get().uri(StrUtil.format(url, 150, 0, System.currentTimeMillis() / 1000)).header("Host", "proxy.finance.qq.com").header("Accept", "*/*").header("User-Agent", "QQStock/11.22.1 (iPad; iOS 15.7; Scale/2.00)").header("Referer", "http://zixuanguapp.finance.qq.com")
                //.bodyValue(student)//
                .retrieve().bodyToMono(String.class)//
                .timeout(Duration.ofSeconds(8)).retry(3).block();
        System.out.println(body);

        TenRespRootDTO<HqKzzDTO> tencentBean = JSON.parseObject(body, new TypeReference<TenRespRootDTO<HqKzzDTO>>() {
        }, Feature.SupportAutoType, Feature.SupportSmartMatch);
        List<HqKzzDTO> rankList = tencentBean.getData().getRankList();

        for (HqKzzDTO hqKzzDTO : rankList) {
            //System.out.println(StrUtil.format("{}|最新价{}|涨跌幅{} |正股涨幅{}", hqKzzDTO.getName(), hqKzzDTO.getZxj(), hqKzzDTO.getZdf(), hqKzzDTO.getStockZdf()));
        }

        List<TenHintDTO> collect = rankList.stream().filter(ia -> NumberUtil.isGreater(ia.getZdf(), new BigDecimal("0"))).map(ib -> TenHintDTO.build(ib))//
                .filter(TenHintDTO::predicate)//
                .sorted((a, b) -> new CompareToBuilder().append(b.getSubZdf(), a.getSubZdf()).toComparison()).filter(ic -> TenTool.bloomFilter.add(StrUtil.format("{}{}", LocalDate.now(), ic.getName())))//
                .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(collect)) return true;

        String dingMsg = collect.stream().map(TenHintDTO::ding).collect(Collectors.joining("\n"));
        String titlea = "🎉实时-涨幅相差(kzz≥1|差≥1.5)";

        System.out.println(StrUtil.format("{}\n  {}\n{}", titlea, DateUtil.now(), dingMsg));
        return false;
    }
}
